package com.kou.backend.controller.file;

import com.kou.backend.api.file.FileOpsClient;
import com.kou.backend.config.SecurityConfig;
import com.kou.backend.dto.user.StoreFileResultDTO;
import com.kou.backend.enums.FileOpsTypeEnum;
import com.kou.backend.request.file.UploadFileRequestDTO;
import com.kou.backend.resposne.ResultResponse;
import com.kou.backend.service.FileStorageService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;

/**
 * @author: kou
 * @since: 2025/6/27 14:19
 */
@RestController
public class FileOpsController implements FileOpsClient {
    @Resource
    private FileStorageService fileStorageService;
    @Resource
    private SecurityConfig securityConfig;

    @PreAuthorize("hasAnyAuthority('all')")
    @Override
    public ResultResponse storeFile(@RequestParam("file") MultipartFile file, UploadFileRequestDTO uploadFileRequestDTO) throws IOException {
        String username = securityConfig.currentUser().getUsername();
        StoreFileResultDTO storeFileResultDTO = fileStorageService.storeFile(file, uploadFileRequestDTO, username);
        if (storeFileResultDTO.isNeedWriteFile()) {
            try {
                //上传文件应在db事务外,异常手动回滚
                fileStorageService.saveFile(file, uploadFileRequestDTO, storeFileResultDTO.getRelativePath(), username);
            } catch (Exception e) {
                fileStorageService.saveErrorDeleteCompensateFileDbInfo(storeFileResultDTO);
                throw e;
            }

        }
        return ResultResponse.success();
    }


    /**
     * 检查文件是否已存在，用于秒传
     *
     * @param fileMd5 文件的MD5值
     * @return 是否存在
     */
    @PreAuthorize("hasAnyAuthority('all')")
    @Override
    public ResultResponse<Boolean> checkFileExists(@RequestParam("fileMd5") String fileMd5) {
        boolean exists = fileStorageService.checkFileExists(fileMd5);
        return ResultResponse.success(exists);
    }

    /**
     * 获取已上传的分片编号列表，用于断点续传
     *
     * @param fileMd5 文件的MD5值
     * @return 已上传的分片编号列表
     */
    @PreAuthorize("hasAnyAuthority('all')")
    @Override
    public ResultResponse<List<Integer>> getUploadedChunks(@RequestParam("fileMd5") String fileMd5) {
        List<Integer> uploadedChunks = fileStorageService.getUploadedChunks(fileMd5);
        return ResultResponse.success(uploadedChunks);
    }

    /**
     * 上传单个分片
     *
     * @param fileMd5     文件的MD5值
     * @param chunkNumber 分片编号
     * @param file        分片文件
     * @return 上传结果
     */
    @PreAuthorize("hasAnyAuthority('all')")
    @Override
    public ResultResponse uploadChunk(@RequestParam("fileMd5") String fileMd5,
                                      @RequestParam("chunkNumber") Integer chunkNumber,
                                      @RequestParam("file") MultipartFile file) throws IOException {
        String username = securityConfig.currentUser().getUsername();
        fileStorageService.uploadChunk(fileMd5, chunkNumber, file, username);
        return ResultResponse.success();
    }

    /**
     * 合并所有分片，生成最终文件
     *
     * @param fileMd5          文件的MD5值
     * @param originalFileName 原始文件名
     * @return 最终文件的相对路径
     */
    @PreAuthorize("hasAnyAuthority('all')")
    @Override
    public ResultResponse<String> mergeChunks(@RequestParam("fileMd5") String fileMd5,
                                              @RequestParam("originalFileName") String originalFileName) throws IOException {
        String username = securityConfig.currentUser().getUsername();
        String relativePath = fileStorageService.mergeChunks(fileMd5, username, originalFileName);
        return ResultResponse.success(relativePath);
    }

    @PreAuthorize("hasAnyAuthority('all')")
    @Override
    public void downloadFile(String fileId, HttpServletResponse response) throws IOException {
        fileStorageService.fileStreamToResponse(fileId, FileOpsTypeEnum.DOWNLOAD_FILE.getFileOpsType(), response);
    }

    @Override
    public ResultResponse deleteFile(String fileId) throws IOException {
        fileStorageService.deleteFile(fileId, securityConfig.currentUser().getUsername());
        return ResultResponse.success();
    }
}
